﻿using System;
using System.Collections;
using System.Web;
using System.IO;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using InfoJetSoft.Service.Entity;
using InfoJetSoft.Service.Worker;
using InfoJetSoft.Service.Util;

namespace InfoJetSoft.Service.Manager
{
    internal class XSNCache
	{
		internal static LicenseInfo licenseInfo = new LicenseInfo(1);
		internal static Hashtable xsnTable = new Hashtable();
		internal static ResolveEventHandler resolveEventHandler = null;
        //CID 0878 //2011.04.23 //Begin
        internal static string HttpContextItemKeyPrefix = "InfoJetService:PublishUrl:";
        //CID 0878 //2011.04.23 //End
        
		static XSNCache()
		{
			resolveEventHandler = new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			System.AppDomain.CurrentDomain.AssemblyResolve += resolveEventHandler;
			System.AppDomain.CurrentDomain.DomainUnload	+= new EventHandler(CurrentDomain_DomainUnload);

			//CID 0275 //2009.04.29 //Begin
			SchemaValidation.IgnoreXhtmlSchemaValidation = ConfigUtil.IgnoreXhtmlSchemaValidation();
			//CID 0275 //2009.04.29 //End
		}

		//CID 0482 //2009.12.30 //Begin
		internal static bool isSPSContext()
		{
			try
			{
				if( System.Environment.Version.Major >= 2 )
				{
					Assembly spAssembly = Assembly.LoadWithPartialName( "Microsoft.SharePoint" );
					if( spAssembly != null )
					{
						if( spAssembly.FullName.EndsWith( "71e9bce111e9429c" ) )
						{
							Type contextType = spAssembly.GetType( "Microsoft.SharePoint.SPContext" );
							if( contextType != null )
							{
								PropertyInfo currentProp = contextType.GetProperty( "Current", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static );
								if( currentProp != null )
								{
									object current = currentProp.GetValue( null, null );
									if( current != null )
									{
										return true;
									}
								}
							}
						}
					}
				}
				else
				{
					//这里直接返回False.
					//暂时SharePoint License不能运行在.NET 1.1的SharePoint上.
					//不过将来升级到.NET 2.0后,就没有这个问题了.
					return false;
				}
				return false;
			}
			catch( Exception e )
			{
				FileLog.log( "isSPSContext " + e.Message );
				return false;
			}
		}
		//CID 0482 //2009.12.30 //End
		
		internal static void license(string licenseKey)
		{
			if(licenseKey == null){
				return;
			}
			licenseKey = licenseKey.Trim();
			if( licenseKey.StartsWith( "ed4+" ) )
			{
				return;
			}
			//CID 0482 //2009.12.30 //Begin
			if( licenseKey.StartsWith( "4oqCV4Kxqg" ) && licenseKey.EndsWith( "WdEGHV8" ) )
			{
				return;
			}
			if( licenseKey.StartsWith( "SHAREPOINT" ) )
			{
				if( isSPSContext() )
				{
					licenseKey = licenseKey.Replace( "SHAREPOINT", "4oqCV4Kxqg" );
					if( !licenseKey.EndsWith( "WdEGHV8" ) )
					{
						return;
					}
				}
				else
				{
                    return;
				}
			}
			if( licenseKey.StartsWith( "INTEGRATION" ) )
			{
				if( isSPSContext() )
				{
					return;
				}
				else
				{
                    //CID 0665 //2010.09.24 //Begin
                    if (licenseKey.StartsWith("INTEGRATION50T"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATION50T", "4oqCV4Kxqg+1V/X");
                    }
                    //CID 0665 //2010.09.24 //Begin
                    //CID 0649 //2010.09.19 //Begin
                    else if (licenseKey.StartsWith("INTEGRATION1ST"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATION1ST", "4oqCV4Kxqg+");
                    }
                    else if (licenseKey.StartsWith("INTEGRATIONMAX"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATIONMAX", "4oqCV4Kxqg+");
                    }
                    else
                    {
					    licenseKey = licenseKey.Replace( "INTEGRATION", "4oqCV4Kxqg+" );
                    }
                    //CID 0649 //2010.09.19 //End
				}
			}
			//CID 0482 //2009.12.30 //End
            //CID 0869 //2011.04.10 //Begin
            else if (licenseKey.StartsWith("INTEGRATING"))
            {
                if (isSPSContext())
                {
                    return;
                }
                else
                {
                    //CID 0665 //2010.09.24 //Begin
                    if (licenseKey.StartsWith("INTEGRATING50T"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATING50T", "4oqCV4Kxqg+1V/X");
                    }
                    //CID 0665 //2010.09.24 //Begin
                    //CID 0649 //2010.09.19 //Begin
                    else if (licenseKey.StartsWith("INTEGRATING1ST"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATING1ST", "4oqCV4Kxqg+");
                    }
                    else if (licenseKey.StartsWith("INTEGRATINGMAX"))
                    {
                        licenseKey = licenseKey.Replace("INTEGRATINGMAX", "4oqCV4Kxqg+");
                    }
                    //CID 1106 //2012.02.22 //Begin
                    else
                    {
                        licenseKey = licenseKey.Replace("INTEGRATINGTEST", "4oqCV4Kxqg+");
                    }
                    //CID 1106 //2012.02.22 //End
                    //CID 0649 //2010.09.19 //End
                }
            }
            //CID 0869 //2011.04.10 //End
			if( licenseKey.Trim().Length <= 0 ){
				return;
			}
			string plain = XSNCache.decrypt( licenseKey );
            if (!plain.Substring(0, 2).Equals("20"))
			{
				return ;
			}
			if (System.Int32.Parse(plain.Substring(4, 2)) >= 13)
			{
				return ;
			}
			if (System.Int32.Parse(plain.Substring(8, 2)) != 21)
			{
				return ;
			}
			string s = plain.Substring(10, 4);
			int count = System.Int32.Parse(plain.Substring(10, 4));
			if (count == 0)
			{
				count = System.Int32.MaxValue;
			}
			licenseInfo = new LicenseInfo(count);
		}
		
		internal static string registerWithMD5( HttpContext httpContext, InfoJetContext jetContext, string publishUrl, byte[] content, string webContext, string md5)
		{
			if( publishUrl == null || md5 == null )
			{
				return null;
			}
			Manifest manifest = (Manifest) xsnTable[publishUrl];
			if (manifest == null)
			{
				//register at the first time.
				return md5register(httpContext, jetContext, publishUrl, content, webContext, md5);
			}
			else
			{
				if ( manifest.MD5 == null)
				{
					return md5register(httpContext, jetContext, publishUrl, content, webContext, md5);
				}
				else
				{
					if (!manifest.MD5.Equals(md5))
					{
						return md5register(httpContext, jetContext, publishUrl, content, webContext, md5);
					}
					else
					{
						return manifest.PublishUrl;
					}
				}
			}
		}
		
		internal static string md5register(HttpContext httpContext, InfoJetContext jetContext, string publishUrl, byte[] content, string webContext, string md5)
		{
			string url = register(httpContext, jetContext, publishUrl, content, webContext);
			if ( url != null )
			{
				Manifest manifest = (Manifest) xsnTable[publishUrl];
				manifest.MD5 = md5;
				return manifest.PublishUrl;
			}
			else
			{
				return null;
			}
		}

		internal static string register( HttpContext httpContext, InfoJetContext jetContext, string publishUrl, byte[] content, string webContext)
		{
			string licenseKey = ConfigUtil.GetSetting( "InfoJetSoft.Service.LicenseKey" );
			if( licenseKey != null )
			{
				license( licenseKey );
			}

			XSNConfig xsnConfig = new XSNConfig();
			xsnConfig.Content = content;
            //CID 0732 //2010.12.19 //Begin
			xsnConfig.WebContext = ScriptHtmlUtil.formatWebContext( httpContext, webContext );
            //CID 0732 //2010.12.19 //End
			Manifest manifest = ManifestLoader.loadManifest(httpContext, jetContext, xsnConfig);
			if( publishUrl != null )
			{
				manifest.PublishUrl = publishUrl;
			}

			//CID 0267 //2009.03.31 //Begin
			string xsnPublishUrl = null;
			lock( xsnTable )
			{
				if (xsnTable.Keys.Count >= licenseInfo.XsnCount)
				{
					if (xsnTable.ContainsKey(manifest.PublishUrl))
					{
						xsnTable[ manifest.PublishUrl ] = manifest;
						xsnPublishUrl = manifest.PublishUrl;
					}
					else
					{
						xsnPublishUrl = null;
					}
				}
				else
				{
					if (xsnTable.ContainsKey(manifest.PublishUrl)) 
					{
						xsnTable[ manifest.PublishUrl ] = manifest;
					}
					else
					{
						xsnTable.Add(manifest.PublishUrl, manifest);
					}
					xsnPublishUrl = manifest.PublishUrl;
				}
			}
			//CID 0267 //2009.03.31 //End

			if( xsnPublishUrl != null )
            {
                //CID 0749 //2011.09.19 //Begin
                if (ConfigUtil.EnableDigitalSignature())
                {
                    MD5 md5 = MD5.Create();
                    byte[] md5Content = md5.ComputeHash(content);
                    StringBuilder md5Buffer = new StringBuilder();
                    for (int i = 0; i < md5Content.Length; i++)
                    {
                        md5Buffer.Append(md5Content[i].ToString("x"));
                    }
                    manifest.Digest = md5Buffer.ToString();
                    manifest.Size = content.Length;
                }
                //CID 0749 //2011.09.19 //End
                //CID 0878 //2011.04.23 //Begin
                //CID 0954 //2011.06.17 //Begin
                string contextKey = HttpContextItemKeyPrefix + xsnPublishUrl;
                if (httpContext.Items.Contains(contextKey))
                {
                    httpContext.Items.Remove(contextKey);
                }
                //CID 0954 //2011.06.17 //End
                httpContext.Items.Add(contextKey, manifest);
                //CID 0878 //2011.04.23 //End
				postRegister( httpContext, manifest );
			}
			
			return xsnPublishUrl;
		}

		//成功注册之后的附加动作。
		internal static void postRegister( HttpContext httpContext, Manifest manifest )
		{
			DataObjectCache.refresh( httpContext, manifest );
		}
		
		internal static string getXSNMD5(string publishUrl)
		{
			if (xsnTable.ContainsKey(publishUrl))
			{
				Manifest manifest = (Manifest) xsnTable[publishUrl];
				return manifest.MD5;
			}
			else
			{
				return null;
			}
		}
		
		internal static void remove(string publishUrl)
		{
			if( xsnTable.ContainsKey( publishUrl ) )
			{
				Manifest manifest = (Manifest)xsnTable[ publishUrl ];
				if( manifest.ResourceFolderPath != null )
				{
					try
					{
						System.IO.Directory.Delete( manifest.ResourceFolderPath, true );
					}
					catch( Exception e )
					{}
				}
			}
			xsnTable.Remove(publishUrl);
		}
		
		internal static bool containsXSN(string publishUrl)
		{
			return xsnTable.ContainsKey(publishUrl);
		}
		
		internal static string[] list()
		{
			string[] keys = new string[xsnTable.Count];
			int i = 0;
			System.Collections.IEnumerator enum_Renamed = xsnTable.Keys.GetEnumerator();
			while (enum_Renamed.MoveNext())
			{
				keys[i] = ((string) enum_Renamed.Current);
				i++;
			}
			return keys;
		}
		
		internal static Manifest getManifest(string publishUrl)
		{
			lock (xsnTable)
			{
				if (xsnTable.Keys.Count > licenseInfo.XsnCount)
				{
					throw new InfoJetException("no xsn " + publishUrl, "MC00");
				}
				Manifest manifest = (Manifest) xsnTable[publishUrl];
                //CID 0878 //2011.04.23 //Begin
                if( manifest == null )
                {
                    manifest = HttpContext.Current.Items[HttpContextItemKeyPrefix + publishUrl] as Manifest;
                }
                //CID 0878 //2011.04.23 //End
                if (manifest == null)
				{
                    throw new InfoJetException("no xsn " + publishUrl, "InfoJetService.MC01");
				}
				return manifest;
			}
		}

		//动态加载managed form code引用的其它程序集.
		internal static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			//这里按程序集名查找,可能找到的是其它表单中的具有相同名字的程序集合.见RefAssemblyForm.xsn,RefAssemblyForm1.xsn
			//如果注册的两个表单中具有两个同一版本单不同内容的程序集,那么先加载的将起作用.
			IEnumerator manifestEnum = xsnTable.Values.GetEnumerator();
			while( manifestEnum.MoveNext() )
			{
				Manifest manifest = (Manifest)manifestEnum.Current;
				if( manifest.ManagedAssembly != null )
				{
					foreach( Assembly refAssembly in manifest.ManagedAssembly.RefAssemblyList )
					{
						if( refAssembly.FullName.Equals( args.Name ) )
						{
							return refAssembly;
						}
					}
				}
			}
			return null;
		}

		internal static void CurrentDomain_DomainUnload(object sender, EventArgs e)
		{
			System.AppDomain.CurrentDomain.AssemblyResolve -= resolveEventHandler;
		}

        //CID 0189 //2010.09.16 //Begin
        public static string decrypt(string encodedText)
        {
            //CID 0662 //2010.09.19 //Begin
            byte[] keyBytes = new byte[24];
            keyBytes[0] = (byte)Int32.Parse("28");
            keyBytes[1] = (byte)Int32.Parse("213");
            keyBytes[2] = (byte)Int32.Parse("127");
            keyBytes[3] = (byte)Int32.Parse("31");
            keyBytes[4] = (byte)Int32.Parse("167");
            keyBytes[5] = (byte)Int32.Parse("70");
            keyBytes[6] = (byte)Int32.Parse("31");
            keyBytes[7] = (byte)Int32.Parse("230");
            keyBytes[8] = (byte)Int32.Parse("193");
            keyBytes[9] = (byte)Int32.Parse("38");
            keyBytes[10] = (byte)Int32.Parse("21");
            keyBytes[11] = (byte)Int32.Parse("84");
            keyBytes[12] = (byte)Int32.Parse("121");
            keyBytes[13] = (byte)Int32.Parse("254");
            keyBytes[14] = (byte)Int32.Parse("203");
            keyBytes[15] = (byte)Int32.Parse("227");
            keyBytes[16] = (byte)Int32.Parse("137");
            keyBytes[17] = (byte)Int32.Parse("1");
            keyBytes[18] = (byte)Int32.Parse("31");
            keyBytes[19] = (byte)Int32.Parse("22");
            keyBytes[20] = (byte)Int32.Parse("158");
            keyBytes[21] = (byte)Int32.Parse("4");
            keyBytes[22] = (byte)Int32.Parse("211");
            keyBytes[23] = (byte)Int32.Parse("97");
            byte[] ivBytes = new byte[8];
            ivBytes[0] = (byte)Int32.Parse("18");
            ivBytes[1] = (byte)Int32.Parse("52");
            ivBytes[2] = (byte)Int32.Parse("86");
            ivBytes[3] = (byte)Int32.Parse("120");
            ivBytes[4] = (byte)Int32.Parse("144");
            ivBytes[5] = (byte)Int32.Parse("171");
            ivBytes[6] = (byte)Int32.Parse("205");
            ivBytes[7] = (byte)Int32.Parse("239");
            //CID 0662 //2010.09.19 //End

            TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();
            provider.Key = keyBytes;
            provider.IV = ivBytes;
            provider.Padding = PaddingMode.None;

            ICryptoTransform transform = provider.CreateDecryptor();
            MemoryStream plainStream = new MemoryStream();
            CryptoStream cytStream = new CryptoStream(plainStream, transform, CryptoStreamMode.Write);
            byte[] outBuffer = new byte[encodedText.Length];
            outBuffer = Convert.FromBase64CharArray(encodedText.ToCharArray(), 0, encodedText.Length);

            cytStream.Write(outBuffer, 0, outBuffer.Length);
            cytStream.FlushFinalBlock();
            return Encoding.Default.GetString(plainStream.GetBuffer(), 0, (int)plainStream.Length).Trim();
        }
        //CID 0189 //2010.09.16 //End
	}
}